using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Core.Graphics.Animations
{
    public enum AnimationTypes
    {
        Loop = 0,
        SeeSaw = 1
    }

    [XmlRoot()]
    public class Animation
    {
        /// <summary>Get the current frame of the animation</summary>
        /// <remarks>If the animation is not running then it returns the default frame</remarks>
        public AnimationFrame CurrentFrame {
            get 
            {
                if (_RunAnimation)
                    return _Frames[_TileAnimationFrame];
                else
                    return _Frames[_DefaultAnimationFrame];
            }
        }

        [XmlArray()]
        public AnimationFrameSeries Frames { get { return _Frames; } set { _Frames = value; } }

        [XmlAttribute("FrameCount")]
        public int TileAnimationFrameCount { get { return _Frames.Count; } }

        [XmlAttribute("FirstFrame")]
        public int TileAnimationFirstFrame { get { return _TileAnimationFirstFrame; } set { _TileAnimationFirstFrame = value; } }

        [XmlAttribute("DefaultFrame")]
        public int DefaultAnimationFrame { get { return _DefaultAnimationFrame; } set { _DefaultAnimationFrame = value; } }

        [XmlAttribute("FrameChangeDelay")]
        public float AnimationDelay { get { return _AnimationDelay; } set { _AnimationDelay = value; } }

        [XmlAttribute("Type")]
        public AnimationTypes AnimationType { get { return _AnimationType; } set { _AnimationType = value; } }

        public int SeeSawDirection { get { return _SeeSawDirection; } }
        public bool RunAnimation { get { return _RunAnimation; } set { _RunAnimation = value; } }
        public float AnimationElapsedTime { get { return _AnimationElapsedTime; } }

        protected int _TileAnimationFrame = 0;          // The current frame of animation we are on.
        protected int _TileAnimationFirstFrame = 0;     // The first frame of the animation within the TileSet, not always the first frame of animation
        protected float _AnimationElapsedTime = 0f;      // How much time has elapsed since we last animated
        protected float _AnimationDelay;            // How much time needs to elapse before we animate 
        protected AnimationTypes _AnimationType;    // What type of Animation this is: loop or seesaw
        protected int _SeeSawDirection;             // Keeps track which way the seesaw loop is moving.  0 for forward 1 for back.
        
        protected bool _RunAnimation;               // Should we currently be running the animation
        protected int _DefaultAnimationFrame;       // What should this animation use as it's starting frame from within the frames provided

        protected AnimationFrameSeries _Frames = new AnimationFrameSeries(); //The frames in the animation

        public Animation(int FirstFrameTileNumber, int FirstShownFrame, float AnimationDelay, AnimationTypes AnimationType)
        {
            //Because we are on a 0 based index subtract 1
            _TileAnimationFirstFrame = FirstFrameTileNumber;
            _AnimationDelay = AnimationDelay;
            _AnimationType = AnimationType;
            _DefaultAnimationFrame = FirstShownFrame;

            //Set the current Animation frame to the default
            SetCurrentFrame(_DefaultAnimationFrame);
        }

        public Animation()
        {
            //For Serialization
        }

        public void SetCurrentFrame(int Frame)
        {
            if (Frame >= 0 && Frame <= TileAnimationFrameCount)
            {
                _TileAnimationFrame = Frame;
            }
        }

        public void GetNextAnimationFrame()
        {
            if (_AnimationType == AnimationTypes.Loop)
            {
                _TileAnimationFrame = (_TileAnimationFrame == TileAnimationFrameCount) ? 0 : _TileAnimationFrame + 1;
            }
            else if (_AnimationType == AnimationTypes.SeeSaw)
            {
                if (_TileAnimationFrame == TileAnimationFrameCount)
                {
                    _SeeSawDirection = 1;
                    _TileAnimationFrame--;
                }
                else if (_TileAnimationFrame == 0)
                {
                    _SeeSawDirection = 0;
                    _TileAnimationFrame++;
                }
                else if (_SeeSawDirection == 1)
                {
                    _TileAnimationFrame--;
                }
                else if (_SeeSawDirection == 0)
                {
                    _TileAnimationFrame++;
                }
            }
        }

        public void Update(float timeElapsed)
        {
            if (_RunAnimation)
            {
                _AnimationElapsedTime += timeElapsed;

                if (_AnimationElapsedTime >= _AnimationDelay)
                {
                    GetNextAnimationFrame();

                    _AnimationElapsedTime = 0.0f;
                }
            }
        }
    }
}
